package com.back.network.netty;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.back.network.netty.constant.Constants;

import io.netty.channel.Channel;
import io.netty.util.AttributeKey;

/**
 * 代理服务连接管理（代理客户端连接+用户请求连接）
 *
 * @author fengfei
 *
 */
public class ProxyChannelManager {

	private static Logger logger = LoggerFactory.getLogger(ProxyChannelManager.class);

	/**
	 * 用户通道
	 */
	private static final AttributeKey<Map<String, Channel>> USER_CHANNELS = AttributeKey.newInstance("user_channels");

	/**
	 * 内网代理信息
	 */
	private static final AttributeKey<String> REQUEST_LAN_INFO = AttributeKey.newInstance("request_lan_info");

	/**
	 * 
	 */
	private static final AttributeKey<List<Integer>> CHANNEL_PORT = AttributeKey.newInstance("channel_port");

	/**
	 * 客户端秘钥
	 */
	private static final AttributeKey<String> CHANNEL_CLIENT_KEY = AttributeKey.newInstance("channel_client_key");

	/**
	 * 根据公网端口获取客户端通道
	 */
	private static Map<Integer, Channel> portCmdChannelMapping = new ConcurrentHashMap<Integer, Channel>();

	/**
	 * 客户端通道
	 */
	private static Map<String, Channel> cmdChannels = new ConcurrentHashMap<String, Channel>();

	/**
	 * 客户端通道
	 */
	private static Map<String, Channel> proxyChannels = new ConcurrentHashMap<String, Channel>();

	/**
	 * 增加代理服务器端口与代理控制客户端连接的映射关系
	 * 
	 * @param ports
	 *
	 * @param ports
	 * @param channel
	 */
	public static void addCmdChannel(String token, Channel channel) {

		if (token == null) {
			throw new IllegalArgumentException("token can not be null");
		}

		channel.attr(CHANNEL_CLIENT_KEY).set(token);
		channel.attr(USER_CHANNELS).set(new ConcurrentHashMap<String, Channel>());
		cmdChannels.put(token, channel);
	}

	/**
	 * 代理客户端连接断开后清除关系
	 *
	 * @param channel
	 */
	public static void removeCmdChannel(Channel channel) {
		logger.warn("channel closed, clear user channels, {}", channel);
		if (channel.attr(CHANNEL_PORT).get() == null) {
			return;
		}

		String clientKey = channel.attr(CHANNEL_CLIENT_KEY).get();
		Channel channel0 = cmdChannels.remove(clientKey);
		if (channel != channel0) {
			cmdChannels.put(clientKey, channel);
		}

		List<Integer> ports = channel.attr(CHANNEL_PORT).get();
		for (int port : ports) {
			Channel proxyChannel = portCmdChannelMapping.remove(port);
			if (proxyChannel == null) {
				continue;
			}

			// 在执行断连之前新的连接已经连上来了
			if (proxyChannel != channel) {
				portCmdChannelMapping.put(port, proxyChannel);
			}
		}

		if (channel.isActive()) {
			logger.info("disconnect proxy channel {}", channel);
			channel.close();
		}

		Map<String, Channel> userChannels = getUserChannels(channel);
		Iterator<String> ite = userChannels.keySet().iterator();
		while (ite.hasNext()) {
			Channel userChannel = userChannels.get(ite.next());
			if (userChannel.isActive()) {
				userChannel.close();
				logger.info("disconnect user channel {}", userChannel);
			}
		}
	}

	/**
	 * 获取客户端通道
	 */
	public static Channel getCmdChannel(Integer port) {
		return portCmdChannelMapping.get(port);
	}

	/**
	 * 获取客户端通道
	 */
	public static Channel getCmdChannel(String token) {
		return cmdChannels.get(token);
	}

	/**
	 * 增加用户连接与代理客户端连接关系
	 *
	 * @param proxyChannel
	 * @param userId
	 * @param userChannel
	 */
	public static void addUserChannelToCmdChannel(Channel cmdChannel, String userId, Channel userChannel) {
		userChannel.attr(Constants.USER_ID).set(userId);
		cmdChannel.attr(USER_CHANNELS).get().put(userId, userChannel);
	}

	/**
	 * 删除用户连接与代理客户端连接关系
	 *
	 * @param proxyChannel
	 * @param userId
	 * @return
	 */
	public static Channel removeUserChannelFromCmdChannel(Channel cmdChannel, String userId) {
		if (cmdChannel.attr(USER_CHANNELS).get() == null) {
			return null;
		}

		synchronized (cmdChannel) {
			return cmdChannel.attr(USER_CHANNELS).get().remove(userId);
		}
	}

	/**
	 * 根据代理客户端连接与用户编号获取用户连接
	 *
	 * @param proxyChannel
	 * @param userId
	 * @return
	 */
	public static Channel getUserChannel(Channel cmdChannel, String userId) {
		return cmdChannel.attr(USER_CHANNELS).get().get(userId);
	}

	/**
	 * 获取用户编号
	 *
	 * @param userChannel
	 * @return
	 */
	public static String getUserChannelUserId(Channel userChannel) {
		return userChannel.attr(Constants.USER_ID).get();
	}

	/**
	 * 获取用户请求的内网IP端口信息
	 *
	 * @param userChannel
	 * @return
	 */
	public static String getUserChannelRequestLanInfo(Channel userChannel) {
		return userChannel.attr(REQUEST_LAN_INFO).get();
	}

	/**
	 * 获取代理控制客户端连接绑定的所有用户连接
	 *
	 * @param cmdChannel
	 * @return
	 */
	public static Map<String, Channel> getUserChannels(Channel cmdChannel) {
		return cmdChannel.attr(USER_CHANNELS).get();
	}

	public static void addProxyChannel(String token, Channel proxyChannel) {
		proxyChannels.put(token, proxyChannel);
	}

	public static Channel getProxyChannel(String token) {
		return proxyChannels.get(token);
	}

}
